#pragma once

/* pollServer */

#include <iostream>
#include <functional>
#include <poll.h>
#include "sock.hpp"

namespace poll_ns
{
    static const uint16_t default_port = 8080;
    static const int fd_num = 1024;
    static const int default_fd = -1;             // 文件描述符默认值

    using func_t = std::function<std::string(const std::string &)>;

    class PollServer
    {
    public:
        PollServer(func_t cb, uint16_t port = default_port)
            : _listen_sockfd(-1), _port(port), _rfds(nullptr), _callback(cb)
        {
        }
        ~PollServer()
        {
            if (_listen_sockfd < 0)
                close(_listen_sockfd);
            if (_rfds)
                delete[] _rfds;
        }

        void initServer()
        {
            // 创建套接字
            _listen_sockfd = Sock::Socket();
            // 绑定端口
            Sock::Bind(_listen_sockfd, _port);
            // 设置为监听状态
            Sock::Listen(_listen_sockfd);

            // 初始化文件描述符数组
            _rfds = new struct pollfd[fd_num];
            for (int i = 0; i < fd_num; ++i)
            {
                ResetFd(i);
            }
            _rfds[0].fd = _listen_sockfd; // 服务器初始只有listen套接字，所以这里只添加listen套接字
            _rfds[0].events = POLLIN;
        }
        void start()
        {
            int timeout = -1;// ms
            while (true)
            {
                // 获取连接

                int n = poll(_rfds, fd_num, timeout);

                switch (n)
                {
                case 0: // 超时返回
                    logMessage(NORMAL, "timeout...");
                    break;
                case -1: // 出错
                    logMessage(WARNING, "poll error, errno: %d, indiacte: %s", errno, strerror(errno));
                    break;
                default: // 有事件就绪
                    logMessage(NORMAL, "have event ready");
                    // 处理事件
                    HandleEvent(); // 就绪事件都在rfds中

                    break;
                }
                // 通信

                // sleep(1);
            }
        }

    private:
        void Accepter(int listensockfd)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = Sock::Accept(_listen_sockfd, &clientip, &clientport);
            if (sockfd < 0)
                return;

            logMessage(NORMAL, "accept link from %s[%d] success", clientip.c_str(), clientport);

            int i = 0;
            for (; i < fd_num; ++i)
            {
                if (_rfds[i].fd != default_fd)
                    continue;
                else
                    break; // 不要直接在这里添加文件描述符，还要考虑容量是否满的问题
            }
            if (i == fd_num) // 文件描述符数组已满，直接断开当前连接
            {
                logMessage(WARNING, "server load is full, please wait...");
                close(sockfd);
            }
            else
            {
                _rfds[i].fd = sockfd; // 添加新文件描述符到文件描述符数组
                _rfds[i].events = POLLIN;
                _rfds[i].revents = 0;
            }
        }
        void ResetFd(int pos)
        {
            _rfds[pos].fd = default_fd;
            _rfds[pos].events = 0;
            _rfds[pos].revents = 0;
        }
        void Recver(int pos)
        {
            // 读取request
            char buffer[1024];
            ssize_t n = recv(_rfds[pos].fd, buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                buffer[n] = 0;
                logMessage(NORMAL, "client >> %s", buffer);
                // std::cout << "client >> " << buffer << std::endl;
            }
            else if (n == 0)
            {
                close(_rfds[pos].fd);

                ResetFd(pos);

                logMessage(NORMAL, "%s", "client quit");
                // std::cout << "client quit" << std::endl;
                return;
            }
            else
            {
                close(_rfds[pos].fd);

                ResetFd(pos);

                logMessage(ERROR, "client link error: %s", strerror(errno));
                // std::cerr << "client link error" << std::endl;
                return;
            }
            // 上面的写法是有问题的，不能保证读取到一个完整的报文。

            // 处理request 有问题
            std::string response = _callback(buffer);

            // 返回respone 有问题
            write(_rfds[pos].fd, response.c_str(), response.size());

            // logMessage(DEBUG, "退出Recver");
        }
        void HandleEvent()
        {
            for (int i = 0; i < fd_num; ++i)
            {
                // 过滤掉非法文件描述符
                if (_rfds[i].fd == default_fd)
                    continue;

                /* 走到这里一定是合法的文件描述符 */
                if(!(_rfds[i].events & POLLIN))
                    continue;
                /* 走到这里一定是合法的文件描述符且我关心它的读事件 */

                // 判断是否是listen套接字就绪
                if (_rfds[i].fd == _listen_sockfd && (_rfds[i].revents & POLLIN)/* listen读事件就绪 */)
                {
                    // 走到这里，listent套接字读事件已就绪

                    Accepter(_listen_sockfd);
                }
                else if (_rfds[i].revents & POLLIN) // 读事件就绪
                {
                    Recver(i);
                }
                else// 事件未就绪
                {};
                // logMessage(DEBUG, "调用Accepter或Recver结束");
            }

            // logMessage(DEBUG, "打印合法文件描述符");
            Print();
        }
        void Print() // 测试用
        {
            std::cout << "fd_array: ";
            for (int i = 0; i < fd_num; ++i)
            {
                if (_rfds[i].fd != default_fd)
                    std::cout << _rfds[i].fd << " ";
            }
            std::cout << std::endl;
        }

    private:
        int _listen_sockfd;
        uint16_t _port;
        struct pollfd* _rfds;
        func_t _callback; // 处理方法，对收到的数据进行业务逻辑的处理
    };
}